package linuxbox.bbs.logic;

import java.util.*;

import org.apache.log4j.*;

import linuxbox.BoxStatic;
import linuxbox.util.*;
import linuxbox.common.*;
import linuxbox.bbs.bean.*;
import linuxbox.bbs.exception.*;
import linuxbox.admin.logic.UserRights;

public class BbsManager {
    public static final int PAGE_SIZE = 5;
    public static final int NO_RIGHT = 100;
    public static final int HAS_CHILD = 101;
    public static final int CAN_DEL = 102;

    private static final char[] ACHTML = {'&', '"', '<', '>', '\n', ' ', '\r'};
    private static final String[] ASTRHTML = {"&amp;", "&quot;", "&lt;", "&gt;", 
                                              "", "&nbsp;", "<br>"};

    protected static BbsManager staticInstance = null;
    protected static Logger logger = Logger.getLogger(BbsManager.class.getName());
    static {
        logger.setLevel(Level.DEBUG);
        logger.addAppender(new ConsoleAppender(new PatternLayout("%5p (%F:%L) - %m%n")));
    }

    protected DbAdapter db = null;
    protected BbsCatHome catHome = null;
    protected BbsMsgHome msgHome = null;

    public static BbsManager getInstance() {
        if (staticInstance == null) {
            staticInstance = new BbsManager();
        }
        
        return staticInstance;
    }

    private BbsManager() {
        init();
    }
    
    private void init() {
        catHome = new BbsCatHome();
        msgHome = new BbsMsgHome();

        /*try {
            //db = new DbAdapter(false);
            //home = new UserCtrlHome(db);
        } catch (Exception e) {
            BoxStatic.logger.debug("UserManager init error: " + e.getMessage());
        }*/
    }
                    
    /*--------- BBS Category Methods --------------*/
    
    public void addBbsCat(BbsCat cat) throws Exception {
        BbsCatHome home = new BbsCatHome();
        home.create(cat);
    }

    public void modifyBbsCat(BbsCat cat) throws Exception {
        BbsCatKey key = new BbsCatKey(cat.getID());
        BbsCatBean bean = new BbsCatBean(key);
        bean.setCatName(cat.getCatName());
        bean.store();
    }

    public void deleteBbsCat(int id) throws Exception {
        BbsCatKey key = new BbsCatKey(id);
        BbsCatHome home = new BbsCatHome();
        home.remove(key);
    }
    
    public String getCatName(int catID) throws BbsManagerException {
        try {
            BbsCatKey key = new BbsCatKey(catID);
            
            key = catHome.findByKey(key);
            BbsCatBean catbean = new BbsCatBean(key);
            return catbean.getCatName();
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public BbsCat[] getAllCatalog() throws BbsManagerException {
        try {
            BbsCat[] cats = null;
            Vector keys = catHome.findBySql(" order by cat_name");

            BbsCatKey pk = null;
            BbsCatBean bean = null;
            int length = keys.size();
            cats = new BbsCat[length];
            
            for (int i = 0; i < length; i++) {
                pk = (BbsCatKey)keys.elementAt(i);
                bean = new BbsCatBean(pk);
                cats[i] = new BbsCat(bean.getCatID(), bean.getCatName());
            }       

            return cats;
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    /*-------------- BBS Message Methods ------------------*/
    
    public long getTopicCount(int catID) throws BbsManagerException { 
        try {
            return msgHome.getTopicCount(catID);
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }
    
    public int getPageCount(int pageSize, int catID) throws BbsManagerException { 
        try {
            long topicCount = msgHome.getTopicCount(catID);
            long pages = 0;
            if (topicCount > 0) { 
                pages = topicCount / (long)pageSize;
                if ((topicCount % (long)pageSize) > 0) {
                    pages++;
                }
            }
            
            return (int)pages;
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public long getMaxTopicID(int catID) throws BbsManagerException {
        try {
            return msgHome.getMaxTopicID(catID);
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public Vector getTopic(long topicID, int catID) throws BbsManagerException {
        try {
            Vector keys = msgHome.getMsgListByTopic(topicID);
            return sortMsgList(keys, null);
    
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    private Vector sortMsgList(Vector originList, DbAdapter db) throws Exception {
        //the originList should order by iIndentLevel
        try {
            BbsMsgKey key = null;
            BbsMsg msg = null;
            
            Vector vctCurrent = new Vector();
            int length = originList.size();
            
            for (int j = 0; j < length; j++) {
                key = (BbsMsgKey)originList.elementAt(j);
                msg = getBbsMsg(key);
                
                int iIndentLevel = msg.getIndLvl();
    
                if (iIndentLevel <= 1) { 
                    vctCurrent.addElement(msg);
                } else {
                    int len = vctCurrent.size();
                        
                    boolean found = false;
                    for (int i = len - 1; i >= 0; i--) {
                        BbsMsg tmpmsg = (BbsMsg)vctCurrent.elementAt(i);
                            
                        if (msg.getParentID() == tmpmsg.getParentID() ||
                            msg.getParentID() == tmpmsg.getID()) {
                            if (i == len - 1)
                                vctCurrent.addElement(msg);
                            else
                                vctCurrent.insertElementAt(msg, i + 1);
                                
                            found = true;
                            break;
                        }
                    }

                    if (!found) {   
                        vctCurrent.addElement(msg);
                    }       
                }
            }
        
            return vctCurrent;
        } catch(Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw e;
        }        
    }

    public BbsMsg getBbsMsg(BbsMsgKey key) throws BbsManagerException {
        try {
            BbsMsgBean bean = new BbsMsgBean(key);

            long lMsgID = bean.getMsgID();
            long lTopicID = bean.getTopicID();
            long lParentID = bean.getParentID();
            int iIndLvl = bean.getIndLvl();
            
            java.sql.Date dtSubDate = bean.getSubDate();
            java.sql.Time tmSubTime = bean.getSubTime();
            String sAuthor = bean.getAuthor();
            String sSubject = bean.getSubject();
            String sMsgBody = bean.getMsgBody();
            int iCategory = bean.getCategory();
            String sCatName = bean.getCatName();
            String sIP = bean.getIP();
    
            BbsMsg msg = new BbsMsg(lMsgID, lTopicID, lParentID, iIndLvl);
            msg.setSubDate(dtSubDate);
            msg.setSubTime(tmSubTime);
            msg.setAuthor(sAuthor);
            msg.setSubject(sSubject);
            msg.setMsgBody(sMsgBody);
            msg.setCategory(iCategory);
            msg.setCatName(sCatName);
            msg.setIP(sIP);
            
            return msg;
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public long getRequestTopicID(long topicID, int catID) throws BbsManagerException {
        try {
            return msgHome.getRequestTopicID(topicID, catID);
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public long getPrevTopic(long topicID, int catID) throws BbsManagerException {
        try {
            BbsMsgKey key = msgHome.getPrevTopic(topicID, catID);
            
            if (key != null) 
                return key.m_lTopicID;
            else
                return -1;
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public long getNextTopic(long topicID, int catID) throws BbsManagerException {
        try {
            BbsMsgKey key = msgHome.getNextTopic(topicID, catID);
            
            if (key != null) 
                return key.m_lTopicID;
            else
                return -1;
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public long getFirstMsgID(long topicID) throws BbsManagerException {
        try {
            return msgHome.getFirstMsgID(topicID);
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }
    
    public void addBbsMsg(BbsMsg msg) throws BbsManagerException {
        try {
            BbsMsgKey key = msgHome.create(msg);
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }
 
    public static String encodeHtml(String s) {
        if (s == null)
            return  "";

        if (s.indexOf(ACHTML[0]) != -1 || s.indexOf(ACHTML[1]) != -1 ||
            s.indexOf(ACHTML[2]) != -1 || s.indexOf(ACHTML[3]) != -1 ||
            s.indexOf(ACHTML[4]) != -1 || s.indexOf(ACHTML[5]) != -1 ||
            s.indexOf(ACHTML[6]) != -1 ) 
            s = replace(s, ACHTML, ASTRHTML);

        return s;
    }

    private static String replace(String s, char[] ac, String[] astr) {
        StringBuffer sb = new StringBuffer();

        for (int i=0; i<s.length(); i++) {
            char c = s.charAt(i);
            boolean blReplaced = false;
   
            for (int j=0; j<ac.length; j++) {
                if (c == ac[j]) {
                    sb.append(astr[j]);
                    blReplaced = true;
                    break;
                }
            }

            if (!blReplaced)
                sb.append(c);
        }

        return sb.toString();
    }

    public int canDelMsg(BoxSession bs, long msgID) throws BbsManagerException {
        int ret = CAN_DEL;

        try {
            BbsMsgKey key = new BbsMsgKey(msgID);
            BbsMsgBean bean = new BbsMsgBean(key);
            String author = bean.getAuthor();
            long topicID = bean.getTopicID();

            if (msgHome.hasChildMsg(topicID, msgID)) {
                ret = HAS_CHILD;
            } else if (!UserRights.isBBSAdmin(bs.getUserRights())
            && !author.equals(bs.getUserName())) {
                ret = NO_RIGHT;
            }       
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
        return ret;
    }

    public void delBbsMsg(long msgID) throws BbsManagerException {
        try {
            BbsMsgKey key = new BbsMsgKey(msgID);
            msgHome.remove(key);
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public ArrayList findNewList(int showMax) throws BbsManagerException {
        try {
            return msgHome.findNewList(showMax);
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public ArrayList queryByType(int catID, int type, String query) throws BbsManagerException {
        try {
            return msgHome.queryByType(catID, type, query);
        } catch (Exception e) {
            BoxStatic.logger.debug(e.getMessage());
            throw new BbsManagerException(e.getMessage());
        }
    }

    public static void main(String[] args) {
        logger.debug("BbsManager test starts ... ");

        try {
            //Class keepStatics = BoxStatic.class;
            String configFile = "main.xml";
            String homeDir = "c:/work/thebox/dist/config/";
    
            BoxInit bi = BoxInit.getInstance(configFile, homeDir);
            bi.zInitSystem();

    	    /*java.sql.Date dtSubDate = new java.sql.Date(System.currentTimeMillis());
            java.sql.Time tmSubTime = new java.sql.Time(System.currentTimeMillis());

            //BbsManager bm = BbsManager.getInstance();
            BbsManager bm = new BbsManager();
            BbsMsg msg = new BbsMsg(-1, -1, -1, 0);
    	
            msg.setSubDate(dtSubDate);
            msg.setSubTime(tmSubTime);
            msg.setSubject("dos test");
            msg.setAuthor("zhangjw");
            msg.setCategory(1);
            msg.setMsgBody("dsfasdfasdfa\nsdfsdasContent");     
            msg.setIP("192.168.100.144");
    					
            bm.addBbsMsg(msg);
    		
            BoxStatic.cleanUp();*/
        } catch (Exception e) {
            e.printStackTrace();
        }
        logger.debug("BbsManager test ends ... ");
        BoxStatic.cleanUp();
        //LogManager.shutdown();
        System.exit(0);
    }
}
